#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <linux/ip.h>
typedef struct {
    uint32_t src_addr;
    uint32_t dst_addr;
    uint8_t zero;
    uint8_t protocol;
    uint16_t tcplen;
} pseudo_header;

typedef struct {
    uint16_t src_port;
    uint16_t dst_port;
    uint32_t seq_num;
    uint32_t ack_num;
    uint8_t data_offset;
    uint8_t flags;
    uint16_t window;
    uint16_t checksum;
    uint16_t urgent_pointer;
    // 不考虑TCP选项和填充
} TCPHeader;

typedef struct {
    uint8_t version:4;
    uint8_t ihl:4;
    // uint8_t vih;
    uint8_t tos;
    uint16_t total_length;
    uint16_t identification;
    uint16_t fragoff;
    uint8_t ttl;
    uint8_t protocol;
    uint16_t checksum;
    uint32_t src_ip;
    uint32_t dst_ip;
} IPHeader;

int is_big_endian() {
    union {
        uint32_t i;
        char c[4];
    } test = {0x01020304};

    return test.c[0] == 1; 
}

uint16_t checksum_compute(uint8_t *ptr, int nbytes)
{

    printf("xxx1 = %d\n", *(uint8_t*)ptr);
    printf("xxx2 = %d\n", *(uint8_t*)((uint8_t*)ptr + 1));
    // printf("xxx3 = %d\n", *ptr >> 4);
    uint8_t aaa[2] = {0x45, 0x00};
    printf("xxx3 = %d\n", *(uint16_t*)aaa);

    *(uint16_t*)aaa = 80;
    printf("xxx4 = %d\n", *(uint8_t*)aaa);
    long sum;
    uint16_t oddbyte;

    sum = 0;
    while (nbytes > 1) {
        sum += *(uint16_t*)ptr++;
        nbytes -= 2;
    }

    if (nbytes == 1) {
        oddbyte = 0;
        *((uint8_t*)&oddbyte) = *(uint8_t*)ptr;
        sum += oddbyte;
    }

    while(sum >> 16) {
        sum = (sum & 0xFFFF) + (sum >> 16);
    }
    // sum = (sum >> 16) + (sum & 0xffff);
    // sum = sum + (sum >> 16);
    // return (uint16_t)~sum;
    return ~sum & 0xffff;
}

int main(int argc, char* argv[])
{

    pseudo_header psh;
    psh.src_addr = htonl(0x7f000001);
    psh.dst_addr = htonl(0x7f000001);
    psh.zero = 0;
    psh.protocol = 6;
    psh.tcplen = htons(40);

    TCPHeader th;
    th.src_port = htons(33436);
    th.dst_port = htons(9999);
    th.seq_num = htonl(0x0f4d5598);
    th.ack_num = htonl(0);
    th.data_offset = 0xa0;
    th.flags = 0x02;
    th.window = htons(0xffd7);
    th.checksum = 0;
    th.urgent_pointer = htons(0);

    uint8_t thopt[20];
    memset(thopt, 0, 20);
    *(uint8_t*)thopt = 0x02;
    *(uint8_t*)(thopt + 1) = 0x04;
    *(uint16_t*)(thopt + 2) = htons(0xffd7);
    *(uint8_t*)(thopt + 4) = 0x04;
    *(uint8_t*)(thopt + 5) = 0x02;
    *(uint8_t*)(thopt + 6) = 0x08;
    *(uint8_t*)(thopt + 7) = 0x0a;
    *(uint32_t*)(thopt + 8) = htonl(0xbd2463f5);
    *(uint32_t*)(thopt + 12) = htonl(0);
    *(uint8_t*)(thopt + 16) = 0x01;
    *(uint8_t*)(thopt + 17) = 0x03;
    *(uint8_t*)(thopt + 18) = 0x03;
    *(uint8_t*)(thopt + 19) = 0x07;

    // checksum_compute((uint16_t*)(thopt), 20);

    char buffer[sizeof(psh) + sizeof(th) + 20];

    memcpy(buffer, &psh, sizeof(psh));
    memcpy(buffer + sizeof(psh), &th, sizeof(th));
    memcpy(buffer + sizeof(psh) + sizeof(th), thopt, 20);

    // 计算ip头校验和
    // IPHeader iph;
    struct iphdr iph;
    iph.version = 4;
    iph.ihl = 5;
    iph.tos = 0;
    iph.tot_len = 60;
    iph.id = 49963;
    iph.frag_off = 0x4000;
    iph.ttl = 64;
    iph.protocol = 6;
    iph.check = 0;
    iph.saddr = 0x7f000001;
    iph.daddr = 0x7f000001;
    uint16_t csum = checksum_compute((uint8_t*)&iph, 20);
    printf("csum = %d\n", csum);

    return 0;
}